package com.ildepinc.persistence.concretes;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.sql.ResultSet;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.HashMap;

import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.MethodOrderer.OrderAnnotation;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;

import com.ildepinc.persistence.abstracts.DaoTableAuditableExpirable;
import com.ildepinc.persistence.concretes.daos.DaoCountry;
import com.ildepinc.persistence.concretes.models.Country;

@TestMethodOrder(OrderAnnotation.class)
class DaoCountryTest {

  private static Persistence persistenceLayer;
  private DaoCountry daoCountry;
  private Timestamp currentTimestamp = new Timestamp(System.currentTimeMillis());
  private Timestamp validToDefault = Utils.addDaysToTimestamp(currentTimestamp, 365);
  private String currentUser = "testUser";

  @BeforeAll
  static void setUpBeforeClass() throws Exception {
    persistenceLayer = new Persistence();
  }

  @Test
  @Order(1)
  void testStartLayer() {
    assertTrue(persistenceLayer.startLayer());
  }

  @Test
  @Order(2)
  void testManualDeleteTableAuditableExpirable() {
    this.daoCountry = (DaoCountry) persistenceLayer.getDaoTableAuditableExpirableMap().get("DaoCountry");
    assertTrue(this.daoCountry instanceof DaoTableAuditableExpirable);
    String deleteSql = this.daoCountry.getTable().getSqlDelete();
    this.daoCountry.setSqlCommand(deleteSql);
    ArrayList<Object> sqlParameters = new ArrayList<Object>();
    sqlParameters.add(2L);
    this.daoCountry.setSqlParameters(sqlParameters);
    Integer rowsAffected = 0;
    try {
      rowsAffected = this.daoCountry.doManualDmlOrDdl();
    } catch (Exception e) {
      e.printStackTrace();
    }
    assertTrue((rowsAffected == 0) || (rowsAffected == 1));
  }

  @Test
  @Order(3)
  void testDeleteTableAuditableExpirable() {
    this.daoCountry = (DaoCountry) persistenceLayer.getDaoTableAuditableExpirableMap().get("DaoCountry");
    assertTrue(this.daoCountry instanceof DaoTableAuditableExpirable);
    Integer rowsAffected = null;
    HashMap<String, Object> primaryKeys = new HashMap<String, Object>();
    primaryKeys.put("ID", 1L);
    try {
      rowsAffected = this.daoCountry.doDelete(primaryKeys);
    } catch (Exception e) {
      e.printStackTrace();
    }
    assertTrue((rowsAffected == 0) || (rowsAffected == 1));
  }

  @Test
  @Order(4)
  void testInsertTableUpdateable() {
    this.daoCountry = (DaoCountry) persistenceLayer.getDaoTableAuditableExpirableMap().get("DaoCountry");
    assertTrue(this.daoCountry instanceof DaoTableAuditableExpirable);
    Integer rowsAffected = null;
    Country country = new Country(
      null, "IT", "Italy",
      this.currentTimestamp, this.currentUser,
      this.currentTimestamp, this.currentUser,
      true, this.currentTimestamp, this.validToDefault,
      "devschema"
    );
    this.daoCountry.setTable(country);
    try {
      rowsAffected = this.daoCountry.doInsert(country, null);
    } catch (Exception e) {
      e.printStackTrace();
    }
    assertEquals(1, rowsAffected);
  }

  @Test
  @Order(5)
  void testUpdateTableUpdatable() {
    this.daoCountry = (DaoCountry) persistenceLayer.getDaoTableAuditableExpirableMap().get("DaoCountry");
    assertTrue(this.daoCountry instanceof DaoTableAuditableExpirable);
    Integer rowsAffected = null;
    Country country = new Country(
      1L, "IT", "Italy",
      this.currentTimestamp, this.currentUser,
      this.currentTimestamp, this.currentUser,
      true, this.currentTimestamp, this.validToDefault,
      "devschema"
    );
    this.daoCountry.setTable(country);
    try {
      rowsAffected = this.daoCountry.doUpdate(country);
    } catch (Exception e) {
      e.printStackTrace();
    }
    assertEquals(1, rowsAffected);
  }

  @Test
  @Order(6)
  void testSelectTableAuditableExpirable() {
    this.daoCountry = (DaoCountry) persistenceLayer.getDaoTableAuditableExpirableMap().get("DaoCountry");
    assertTrue(this.daoCountry instanceof DaoTableAuditableExpirable);
    Country country = null;
    HashMap<String, Object> primaryKeys = new HashMap<String, Object>();
    primaryKeys.put("ID", 1L);
    try {
      country = (Country) this.daoCountry.doSelect(primaryKeys);
    } catch (Exception e) {
      e.printStackTrace();
    }
    assertEquals(1L, country.getId());
  }

  @Test
  @Order(7)
  void testManualInsertTableAuditableExpirable() {
    this.daoCountry = (DaoCountry) persistenceLayer.getDaoTableAuditableExpirableMap().get("DaoCountry");
    assertTrue(this.daoCountry instanceof DaoTableAuditableExpirable);
    String insertSql = this.daoCountry.getTable().getSqlInsert();
    this.daoCountry.setSqlCommand(insertSql);
    ArrayList<Object> sqlParameters = new ArrayList<Object>();
    sqlParameters.add(2L);
    sqlParameters.add("GB");
    sqlParameters.add("Great Britain");
    sqlParameters.add(this.currentTimestamp);
    sqlParameters.add(this.currentUser);
    sqlParameters.add(this.currentTimestamp);
    sqlParameters.add(this.currentUser);
    sqlParameters.add(true);
    sqlParameters.add(this.currentTimestamp);
    sqlParameters.add(this.validToDefault);
    this.daoCountry.setSqlParameters(sqlParameters);
    Integer rowsAffected = 0;
    try {
      rowsAffected = this.daoCountry.doManualDmlOrDdl();
    } catch (Exception e) {
      e.printStackTrace();
    }
    assertEquals(1, rowsAffected);
  }

  @Test
  @Order(8)
  void testManualUpdateTableAuditableExpirable() {
    this.daoCountry = (DaoCountry) persistenceLayer.getDaoTableAuditableExpirableMap().get("DaoCountry");
    assertTrue(this.daoCountry instanceof DaoTableAuditableExpirable);
    String updateSql = this.daoCountry.getTable().getSqlUpdate();
    this.daoCountry.setSqlCommand(updateSql);
    ArrayList<Object> sqlParameters = new ArrayList<Object>();
    sqlParameters.add("GB");
    sqlParameters.add("Great Britain");
    sqlParameters.add(this.currentTimestamp);
    sqlParameters.add(this.currentUser);
    sqlParameters.add(true);
    sqlParameters.add(this.currentTimestamp);
    sqlParameters.add(this.validToDefault);
    sqlParameters.add(2L);
    this.daoCountry.setSqlParameters(sqlParameters);
    Integer rowsAffected = 0;
    try {
      rowsAffected = this.daoCountry.doManualDmlOrDdl();
    } catch (Exception e) {
      e.printStackTrace();
    }
    assertEquals(1, rowsAffected);
  }

  @Test
  @Order(9)
  void testManualSelectTableAuditableExpirable() {
    this.daoCountry = (DaoCountry) persistenceLayer.getDaoTableAuditableExpirableMap().get("DaoCountry");
    assertTrue(this.daoCountry instanceof DaoTableAuditableExpirable);
    String selectSql = this.daoCountry.getTable().getSqlSelect();
    this.daoCountry.setSqlCommand(selectSql);
    ArrayList<Object> sqlParameters = new ArrayList<Object>();
    sqlParameters.add(2L);
    this.daoCountry.setSqlParameters(sqlParameters);
    ResultSet resultSet = null;
    Long retriviedId = 0L;
    try {
      resultSet = this.daoCountry.doManualSelect();
      resultSet.first();
      retriviedId = resultSet.getLong(1);
    } catch (Exception e) {
      e.printStackTrace();
    }
    assertEquals(2L, retriviedId);
  }

  @Order(10)
  void testStopLayer() {
    assertTrue(persistenceLayer.stopLayer());
  }

  @AfterAll
  static void tearDownAfterClass() throws Exception {
    persistenceLayer = null;
  }

}
